package org.sean.framework.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.sean.framework.bean.PageData;
import org.sean.framework.bean.PageQuery;
import org.sean.framework.service.CrudService;
import org.sean.framework.util.ObjectUtil;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * CRUD基础服务类
 *
 * @param <M> Mapper
 * @param <E> 数据库实体
 * @param <D> 传输层实体
 * @param <Q> 查询参数
 * @author sean.xie
 */
public abstract class CrudServiceImpl<M extends BaseMapper<E>, E, D, Q extends PageQuery>
        extends ServiceImpl<M, E> implements CrudService<E, D, Q> {

    @SuppressWarnings("unchecked")
    protected Class<D> currentDTOClass() {
        return (Class<D>) ReflectionKit.getSuperClassGenericType(getClass(), null, 2);
    }

    /**
     * 获取分页对象
     *
     * @param pageQuery    分页查询参数
     * @param defaultField 默认排序字段
     * @param isAsc        排序方式
     * @return 分页数据
     */
    protected IPage<E> getPage(PageQuery pageQuery, String defaultField, boolean isAsc) {
        //分页对象
        Page<E> page = new Page<>(pageQuery.getPage(), pageQuery.getSize());

        //排序字段
        String field = pageQuery.getSortField();
        String order = pageQuery.getSortOrder();

        //前端字段排序
        if (StringUtils.isNotBlank(field) && StringUtils.isNotBlank(order)) {
            if (PageQuery.ORDER_ASC.equalsIgnoreCase(order)) {
                return page.addOrder(OrderItem.asc(field));
            } else {
                return page.addOrder(OrderItem.desc(field));
            }
        }

        //没有排序字段，则不排序
        if (StringUtils.isBlank(defaultField)) {
            return page;
        }

        //默认排序
        if (isAsc) {
            page.addOrder(OrderItem.asc(defaultField));
        } else {
            page.addOrder(OrderItem.desc(defaultField));
        }

        return page;
    }


    protected <C> PageData<C> getPageData(List<?> list, long total, long current, Class<C> target) {
        List<?> raw = list;
        List<C> targetList = ObjectUtil.convert(raw, target);
        return PageData.<C>builder().count(total).list(targetList).page(current).build();
    }

    protected <C> PageData<C> getPageData(IPage<E> page, Class<C> target) {
        return getPageData(page.getRecords(), page.getTotal(), page.getCurrent(), target);
    }

    protected Map<String, Object> paramsToLike(Map<String, Object> params, String... likes) {
        for (String like : likes) {
            String val = (String) params.get(like);
            if (StringUtils.isNotBlank(val)) {
                params.put(like, "%" + val + "%");
            } else {
                params.put(like, null);
            }
        }
        return params;
    }

    @Override
    public PageData<D> pageDTO(Q query) {
        IPage<E> page = super.page(getPage(query, null, true), getWrapper(query));
        return getPageData(page, currentDTOClass());
    }

    @Override
    public PageData<D> pageDTO(Q query, Wrapper<E> queryWrapper) {
        IPage<E> page = super.page(getPage(query, null, true), queryWrapper);
        return getPageData(page, currentDTOClass());
    }

    @Override
    public List<D> listDTO(Q query) {
        List<E> entityList = super.list(getWrapper(query));
        return ObjectUtil.convert(entityList, currentDTOClass());
    }

    @Override
    public List<D> listByWrapper(Wrapper<E> queryWrapper) {
        return ObjectUtil.convert(super.list(queryWrapper), currentDTOClass());
    }

    /**
     * 查询条件
     * 只适用于以下方法
     * {@link #listDTO(PageQuery) }
     * {@link #pageDTO(PageQuery)}
     *
     * @param query 条件
     * @return 查询结果
     */
    protected abstract Wrapper<E> getWrapper(Q query);

    @Override
    public D getDTO(Long id) {
        E entity = super.getById(id);
        return ObjectUtil.convert(entity, currentDTOClass());
    }

    @Override
    public E saveDTO(D data) {
        E entity = ObjectUtil.convert(data, currentModelClass());
        if (super.save(entity)) {
            return entity;
        }
        return null;
    }

    @Override
    public boolean updateDTO(D dto) {
        E entity = ObjectUtil.convert(dto, currentModelClass());
        return updateById(entity);
    }

    @Override
    public boolean deleteByIds(Long[] ids) {
        return super.removeByIds(Arrays.asList(ids));
    }

    @Override
    public boolean deleteByWrapper(Wrapper<E> query) {
        return super.remove(query);
    }

}
